#ifndef _ENERGY_H_
#define _ENERGY_H_

#include <vector>
#include <complex>
#include <algorithm>
#include <functional>
#include <numeric>
#include <iostream>
#include "complex_ops.h"
#include "NumericTypes.h"



struct Energy
{
public:

    const char* getName()
    {
        const static char name[] = "Energy"; 
        return name;
    }
    
    template
    <
        typename SignalSystem
    >
    double operator()(SignalSystem& sys)
    {
        using namespace std;
        
        double sum = 0;
        
        for(int i =0; i < sys.size() ; ++i)
        {
            vector<double> rslt(sys[i].size());
            
            transform(
                sys[i].begin(), sys[i].end(),
                rslt.begin(),
                absolute<complex<double>,double>()
            );
        
            std::binder2nd
            <
                power<int, double>
            >
            power2(
                power<int, double>(),
                2
            );
        
            transform(
                rslt.begin(), rslt.end(),
                rslt.begin(),
                power2
            );
      
            sum =
                accumulate(
                    rslt.begin(), rslt.end(),
                    sum
                );
        }
        
        if (sum < 1)
            sum = 1;
            
        return sum;
    }
};

struct EnergyN
{
public:

    const char* getName()
    {
        const static char name[] = "EnergyN"; 
        return name;
    }
    
    template
    <
        typename SignalSystem
    >
    double operator()(SignalSystem& sys)
    {
        return 1.0 - exp(1.0 - energy(sys));
    }
    
    Energy energy;
};

#endif //_ENERGY_H_
